package bankrmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;



/**
 * Applications r�parties
 * TP 3
 * Gestion de comptes bancaires, Java RMI
 * 
 * Ensemble des comptes g�r�s par la banque
 * 
 * Classe impl�mentant l'interface Java RMI "BankInterface"
 * 
 * Cette classe permettra d'instancier un servant dans le programme principal du serveur.
 * 
 * @author Toto
 * @version 1.0
 */
public class BankAccountsImpl extends UnicastRemoteObject implements BankInterface {

	private static final long serialVersionUID = -4441572042898914599L;
	

	/**
	 * Table des comptes
	 */
	private HashMap<String, Account> allAccounts; 


	/**
	 * Constructeur par D�faut
	 */
	public BankAccountsImpl() throws RemoteException {
		allAccounts = new HashMap<String, Account>();
	}


	/**
	 * Ouverture d'un compte.
	 * 
	 * La m�thode r�alise la v�rification d�un compte ayant d�ja le m�me nom 
	 * de titulaire, auquel cas elle l�ve une exception de type	BankingException 
	 * et dans le cas contraire cr�e le compte et l�enregistre dans	la table allAccounts.
	 * 
	 * Ici on "synchronize" la m�thode. C'est peut �tre "brutal" mais cela �vite le cas extreme
	 * d'ouverture simultan� de 2 nouveaux comptes avec les m�mes informations.
	 * 
	 * (on permet l'ouverture d'un seul compte � la fois)
	 * "synchronized" permet d'�tre seul � ex�cuter la m�thode "openAccount" de 
	 * l'objet BankAccount cr�� dans le main du serveur.
	 * 
	 * 
	 * @param name
	 * @param password
	 * @return float Solde du compte
	 * @throws BankException
	 */
	synchronized public float openAccount(String name, String password) 
	throws RemoteException, BankException {
		float solde = -1;
		if(!allAccounts.containsKey(name)) {
			Account account = new Account(name, password);
			allAccounts.put(name, account);
			solde = 0f;
		}
		else throw new BankException(BankUtil.EXISTANT);
		return solde;
	}


	/**
	 * M�thode utilitaire de v�rification d�existence de compte 
	 * et de validation du mot de passe.
	 * 
	 * Si le compte nomm� "name" n�existe pas (dans allAccounts) ou si le mot de passe
	 * password est diff�rent de celui trouv� pour ce compte dans allAccounts,
	 * la m�thode g�n�re une exception de type BankingException. 
	 * Sinon, elle renvoie une r�f�rence sur l�objet de type Account correspondant.
	 * 
	 * @param name
	 * @param password
	 * @return Account l'objet Account trouv� (selon le nom, et si mot de passe correct)
	 * @throws BankException
	 */
	public Account verify(String name, String password)
	throws RemoteException, BankException {
		Account account = null;
		if(allAccounts.containsKey(name)) {
			account = allAccounts.get(name);
			if(account.verifyPassword(password) == false) {
				account = null;
				throw new BankException(BankUtil.INVPASSWORD);
			}
		}
		else throw new BankException(BankUtil.NONEXISTANT);
		return account;
	}


	/**
	 * Fermeture d'un compte.
	 * 
	 * Elle effectue une v�rification � l�aide de verify(...), 
	 * retire le compte de la table allAccounts, 
	 * et renvoie le montant disponible.
	 * 
	 * @param name
	 * @param password
	 * @return float Montant disponible
	 * @throws BankException
	 */
	public float closeAccount(String name, String password)
	throws RemoteException, BankException {
		float solde = -1f;
		Account account = null;
		if((account = verify(name,password)) != null) {
			synchronized(account) {
				solde = account.getBalance();
				allAccounts.remove(name);
			}
			account = null;
			//L'objet account a �t� retir� de allAccounts, et � pr�sent il ne reste plus de r�f sur cet objet. 
			//Il sera donc d�truit/r�cup�r� par le garbage collector.
		}
		return solde;
	}


	/**
	 * D�pot sur un compte.
	 * 
	 * Elle effectue une v�rification � l�aide de verify(...) 
	 * et incr�mente le solde du montant 'amount' d�pos�.
	 * 
	 * @param name
	 * @param password
	 * @param amount
	 * @return float Nouveau solde
	 * @throws BankException
	 */
	public float deposit(String name, String password, float amount) 
	throws RemoteException, BankException {
		float solde = -1f;
		Account account = null;
		if((account = verify(name,password)) != null) {
			synchronized(account) { // permet d'�tre le seul � acc�der/modifier l'objet "account"
				solde = account.deposit(amount);
			}
		}
		return solde;
	}


	/**
	 * Retrait sur un compte.
	 * 
	 * Elle effectue une v�rification � l�aide de verify(...), v�rifie que 
	 * le solde est suffisant pour le montant du retrait (dans le cas contraire, 
	 * elle gen�re une exception de type BankingException), d�cr�mente le solde 
	 * du montant amount et	renvoie le montant retir�.
	 * 
	 * @param name
	 * @param password
	 * @param amount
	 * @return float Nouveau solde
	 * @throws BankException
	 */
	public float withdraw(String name, String password, float amount)
	throws RemoteException, BankException {
		float solde = -1f;
		Account account = null;
		if((account = verify(name,password)) != null) {
			synchronized(account) {
				solde = account.withdraw(amount);
				if(solde==-1f) 
					throw new BankException(BankUtil.NEGBALANCE);
			}
		}
		return solde;
	}


	/**
	 * Obtention du solde d�un compte.
	 * 
	 * Elle effectue une v�rification � l�aide de verify(...), 
	 * puis renvoie le solde du	compte.
	 * 
	 * @param name
	 * @param password
	 * @return float Le solde
	 * @throws BankException
	 */
	public float getBalance(String name, String password)
	throws RemoteException, BankException {
		float solde = -1f;
		Account account = null;
		if((account = verify(name,password)) != null) {
			synchronized(account) {
				solde = account.getBalance();
			}
		}
		return solde;
	}


}
